/*
 * pcbH.cpp
 *
 *  Created on: Dec 9, 2012
 *      Author: omnia
 */

#include             "global.h"
#include             "syscalls.h"
#include             "protos.h"
#include			"Definitions.h"

void lockReady(void) {
	INT32 LockResult;
	ZCALL(Z502_READ_MODIFY( MEMORY_INTERLOCK_BASE + 1,1,true, &LockResult ));
}
void unlockReady(void) {
	INT32 LockResult;
	ZCALL(Z502_READ_MODIFY( MEMORY_INTERLOCK_BASE + 1,0,true, &LockResult ));
}

void ready_to_Running(void) {
	INT32 LockResult;
	ZCALL(Z502_READ_MODIFY( MEMORY_INTERLOCK_BASE + 1, 1,true, &LockResult ));
	PCB *current = pidList;
	while (current != NULL) {
		if (current->processId == current_PCB->processId) {
			current_PCB->state = RUNNING_STATE;
		} else if (current->state == RUNNING_STATE) {
			current_PCB->state = READY_STATE;
		}
		current = (PCB*) current->next;
	}
	ZCALL(Z502_READ_MODIFY( MEMORY_INTERLOCK_BASE + 1, 0, true, &LockResult ));
}

PCB *ready_to_Wait ( INT32 remove_id ){
	PCB* current = pidList;
	while (current != NULL) {
		if (current->processId == remove_id) {
			current->state = WAITING_STATE;
			return current;
		}
		current = (PCB*) current->next;
	}
	return NULL;
}

PCB* wait_to_ready(INT32 givenID) {
	PCB* current = pidList;
	while (current != NULL) {
		if (current->processId == givenID) {
			current->state = READY_STATE;
			return current;
		}
		current = (PCB*) current->next;
	}
	return NULL;
}

INT32 updatePriority(INT32 process_ID, INT32 new_priority) {
	lockReady();
	PCB *ptrCheck = pidList;

	while (ptrCheck != NULL) {
		if (ptrCheck->processId == process_ID) {
			ptrCheck->pri = new_priority;
			unlockReady();
			return 1;
		}
		ptrCheck = (PCB*) ptrCheck->next;
	}
	unlockReady();
	return -1;
}

//fe el a5er we ana ba3del el current lazem a3mel check law mesh hey hey yeb2a laze
// a3'ayraha get_current_PCB
void change_Priority(INT32 process_ID, INT32 new_priority, INT32 *error) {
	PCB * switchPCB;
		INT32	status;

		//New priority exceeds limit
		if (new_priority > MAX_PRIO){

			(*error) = ERR_BAD_PARAM;
			return;
		}
		//if pid -1, UPDATE SELF
		if ( process_ID == -1 ){
			//UPDATE SELF, or return error
			process_ID = current_PCB->processId;
			CALL( status = updatePriority(process_ID, new_priority) );
			if (status == 1) (*error) = ERR_SUCCESS;
			//ERROR
			else{

				(*error) = ERR_BAD_PARAM;
				return;
			}
		}
		//else, update PID
		else{
			CALL( status = updatePriority(process_ID, new_priority) );
			if (status == 1) (*error) = ERR_SUCCESS;
			//ERROR
			else{

				(*error) = ERR_BAD_PARAM;
				return;
			}
		}

		//SORT the Ready Queue based on the new priorities
		ZCALL( lockReady() );
		CALL( ready_sort() );
		ZCALL( unlockReady() );



		//GET READY PCB TO RUN
		//If the ready PCB is already running, return
		//Else switch to the new process
		CALL( switchPCB = get_readyPCB() );
		if (switchPCB == NULL) EVENT_IDLE();
		else if (switchPCB->processId == current_PCB->processId) return;
		if (switchPCB != NULL) CALL( switch_Savecontext(switchPCB) );
}
